<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta name="author" content="lijinbo" />
    <title>fn_bind的理解</title>
  </head>

  <body>
    <div>看控制台</div>
    <button class="someClass">点击</button>
    <script>
      // bind 的用处是绑定this指向，示例

      var altwrite = document.write
      // altwrite("hello"); // Illegal invocation (非法调用)
      // 因为单独调用改变了this的指向

      altwrite.bind(document)('hello') // 执行前绑定this指向document
      // altwrite.call(document, "hello");   // 执行前改变this指向document

      // 其实上面的操作都是一样的，就好像捆到和绑到一样的(●ˇ∀ˇ●)

      // 示例用法2，保存this
      var foo = {
        bar: 1,
        eventBind: function () {
          $('.someClass').on(
            'click',
            function (event) {
              /* Act on the event */
              console.log(this.bar) // 1
            }.bind(this)
          )
        }
      }
      foo.eventBind()

      /**
       * 浏览器不持支bind方法的拓展
       */
      if (!Function.prototype.bind) {
        Function.prototype.bind = function (oThis) {
          if (typeof this !== 'function') {
            // closest thing possible to the ECMAScript 5
            // internal IsCallable function
            throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable')
          }

          var aArgs = Array.prototype.slice.call(arguments, 1),
            fToBind = this,
            fNOP = function () {},
            fBound = function () {
              // this instanceof fBound === true时,说明返回的fBound被当做new的构造函数调用
              return fToBind.apply(
                this instanceof fBound ? this : oThis,
                // 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
                aArgs.concat(Array.prototype.slice.call(arguments))
              )
            }

          // 维护原型关系
          if (this.prototype) {
            // Function.prototype doesn't have a prototype property
            fNOP.prototype = this.prototype
          }
          // 下行的代码使fBound.prototype是fNOP的实例,因此
          // 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
          fBound.prototype = new fNOP()

          return fBound
        }
      }
    </script>
  </body>
</html>
